﻿using System;
using System.Collections.Generic;
using Projecturo.ProjecturoClient.Command;
using System.Windows.Input;
using System.Reflection;
using Projecturo.Model;
using Neits.PersistenceService.Providers;
using Projecturo.ProjecturoClient.Connection;
using System.Collections.ObjectModel;

namespace Projecturo.ProjecturoClient.ViewModel.Project
{
    public class ProjectManagementViewModel : WorkspaceViewModel
    {
        private Model.Project project;
        private IList<Category> categories;
        private IList<Model.Version> versions;
        private ObservableCollection<ViewModelBase> ticketStates = new ObservableCollection<ViewModelBase>();
        private IList<TicketStateMapping> stateMappings;

        private DelegateCommand<long> openMilestoneCommand;
        private DelegateCommand<String> addCategoryCommand;
        private DelegateCommand<String> addVersionCommand;
        private DelegateCommand addMilestoneCommand;

        public ProjectManagementViewModel()
        {
            DisplayName = "Project Management";
        }

        public string Name
        {
            get { return project.Name; }
        }

        public Model.Project Project
        {
            get { return project; }
            set {
                if (project == value)
                    return;
                project = value;
                OnPropertyChanged("Project");
            }
        }

        public ICommand OpenMilestoneCommand
        {
            get
            {
                if (openMilestoneCommand == null)
                    openMilestoneCommand = new DelegateCommand<long>(OpenMilestone);
                return openMilestoneCommand;
            }
        }

        public ICommand AddCategoryCommand
        {
            get
            {
                if (addCategoryCommand == null)
                    addCategoryCommand = new DelegateCommand<String>(CreateCategory, CanCreateCategory);
                return addCategoryCommand;
            }
        }

        private bool CanCreateCategory(String categoryName)
        {
            return !String.IsNullOrEmpty(categoryName) && project.Id > 0;
        }

        private void CreateCategory(String categoryName)
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(Category), this);
            viewModel.SetParent(project);
            SetProperty(viewModel, "Name", categoryName);
            viewModel.SaveCommand.Execute(null);
            LoadCategories();
            OnPropertyChanged("Categories");
        }

        private static void SetProperty(object obj, string propertyName, object value)
        {
            PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);
            if (propertyInfo != null)
            {
                propertyInfo.SetValue(obj, value, null);
            }
        }

        public ICommand AddMilestoneCommand
        {
            get
            {
                if (addMilestoneCommand == null)
                    addMilestoneCommand = new DelegateCommand(AddMilestone, CanAddMilestone);
                return addMilestoneCommand;
            }
        }

        private void AddMilestone()
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(Milestone), this);
            viewModel.SetParent(project);
            AddToWorkspace(viewModel as WorkspaceViewModel, ViewModelReference, viewModel as WorkspaceViewModel);
        }

        private bool CanAddMilestone()
        {
            return project != null;
        }

        public ICommand AddVersionCommand
        {
            get
            {
                if (addVersionCommand == null)
                    addVersionCommand = new DelegateCommand<String>(CreateVersion, CanCreateVersion);
                return addVersionCommand;
            }
        }

        private bool CanCreateVersion(String versionName)
        {
            return !String.IsNullOrEmpty(versionName) && project.Id > 0;
        }

        private void CreateVersion(String versionName)
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(Model.Version), this);
            viewModel.SetParent(project);
            SetProperty(viewModel, "Name", versionName);
            viewModel.SaveCommand.Execute(null);
            LoadVersions();
            OnPropertyChanged("Versions");
        }

        private void OpenMilestone(long id)
        {
            ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(Milestone), this);
            viewModel.SetModel(id);
            AddToWorkspace(viewModel as WorkspaceViewModel, ViewModelReference, viewModel as WorkspaceViewModel);
        }

        public IList<Milestone> Milestones
        {
            get
            {
                return project.Milestones;
            }
        }

        public IList<Model.Version> Versions
        {
            get
            {
                LoadVersions();
                return versions;
            }
        }

        private void LoadVersions()
        {
            var filter = new HqlFilter("from Version v where v.Project.Id = " + project.Id);
            versions = Connector.Connectivity.Storage.GetList<Model.Version>(filter);
        }

        private void LoadProject()
        {
            project = Connector.Connectivity.Storage.Get<Model.Project>(project.Id);
        }

        public IList<Category> Categories
        {
            get
            {
                LoadCategories();
                return categories;
            }
        }

        private void LoadCategories()
        {
            var filter = new HqlFilter("from Category c where c.Project.Id = " + project.Id);
            categories = Connector.Connectivity.Storage.GetList<Category>(filter);
        }

        public ObservableCollection<ViewModelBase> TicketStates
        {
            get
            {
                if (ticketStates == null || ticketStates.Count == 0)
                    UpdateTicketStates();
                return ticketStates;
            }
        }

        public IList<TicketStateMapping> StateMappings
        {
            get
            {
                if (stateMappings == null)
                    UpdateTicketStateMappings();
                return stateMappings;
            }
            set
            {
                stateMappings = value;
            }
        }

        private IList<TicketState> GetTicketStates()
        {
            var filter = new HqlFilter("from TicketState ts where ts.Project.Id = " + project.Id);
            return Connector.Connectivity.Storage.GetList<TicketState>(filter);
        }

        private void UpdateTicketStates()
        {
            var filter = new HqlFilter("from TicketState ts where ts.Project.Id = " + project.Id);
            IList<TicketState> states = Connector.Connectivity.Storage.GetList<TicketState>(filter);

            ticketStates.Clear();
            foreach (TicketState state in states)
            {
                ViewModelBase viewModel = ViewModelManager.Instance.CreateViewModel(typeof(TicketState), this);
                viewModel.SetModel(state);
                ticketStates.Add(viewModel);
            }
        }

        private void UpdateTicketStateMappings()
        {
            var filter = new HqlFilter("from TicketStateMapping tsm where tsm.State.Project.Id = " + project.Id);
            IList<TicketStateMapping> mappings = Connector.Connectivity.Storage.GetList<TicketStateMapping>(filter);

            if (mappings == null || mappings.Count == 0)
                stateMappings = BuildStateMappings();
            else
                stateMappings = mappings;
        }

        private IList<TicketStateMapping> BuildStateMappings()
        {
            IList<TicketState> states = GetTicketStates();
            IList<TicketStateMapping> mappings = new List<TicketStateMapping>();
            if (states != null && states.Count > 0)
            {
                foreach (TicketState state in states)
                {
                    foreach (TicketState mappingState in states)
                    {
                        if (!state.Name.Equals(mappingState.Name))
                        {
                            TicketStateMapping mapping = new TicketStateMapping();
                            mapping.State = state;
                            mapping.MappingState = mappingState;
                            mapping.IsAllowed = true;

                            mappings.Add(mapping);
                        }
                    }
                }
            }
            return mappings;
        }

        public override void SetModel(object model)
        {
            project = model as Model.Project;
        }

        protected override void Save()
        {
            Connector.Connectivity.Storage.Save(project);
            foreach (TicketStateMapping mapping in StateMappings)
                Connector.Connectivity.Storage.Save(mapping);
        }

        public override void Update()
        {
            base.Update();
            LoadCategories();
            LoadVersions();
            LoadProject();
        }
    }
}
